package cn.vconinfo.base.utils;

import lombok.extern.slf4j.Slf4j;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 *  将对象进行系列化
 *
 */
@Slf4j
public class SerializeUtils {

    private final static ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        objectMapper.configure(JsonParser.Feature.INTERN_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.CANONICALIZE_FIELD_NAMES, true);
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static String encode(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonGenerationException e) {
            log.error("encode(Object)", e); //$NON-NLS-1$
        } catch (JsonMappingException e) {
            log.error("encode(Object)", e); //$NON-NLS-1$
        } catch (IOException e) {
            log.error("encode(Object)", e); //$NON-NLS-1$
        }
        return null;
    }

    /**
     * 将json string反序列化成对象
     *
     * @param json
     * @param valueType
     * @return
     */
    public static <T> T decode(String json, Class<T> valueType) {
        try {
            return objectMapper.readValue(json, valueType);
        } catch (JsonParseException e) {
            log.error("decode(String, Class<T>)", e);
        } catch (JsonMappingException e) {
            log.error("decode(String, Class<T>)", e);
        } catch (IOException e) {
            log.error("decode(String, Class<T>)", e);
        }
        return null;
    }

    /**
     * 把对象虚拟化成String，并将序列化的结果编码.
     *
     * @param object
     *            要序列化的对象
     * @return 序列化的结果
     */
    public static String SerializeToString(Object object) {
        String serStr = null;

        if (null == object) {
            log.error("SerializeToString input Object is null!");
            return serStr;
        }

        ByteArrayOutputStream byteArrayOutStream = null;
        ObjectOutputStream objOutStream = null;

        try {
            byteArrayOutStream = new ByteArrayOutputStream();
            objOutStream = new ObjectOutputStream(byteArrayOutStream);
            objOutStream.writeObject(object);
            serStr = byteArrayOutStream.toString("ISO-8859-1");
            serStr = URLEncoder.encode(serStr, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != objOutStream) {
                try {
                    objOutStream.close();
                } catch (IOException e) {
                }
            }
            if (null != byteArrayOutStream) {
                try {
                    byteArrayOutStream.close();
                } catch (IOException e) {
                }
            }
        }
        return serStr;
    }

    /**
     * 把对象从字符串中反序列化.
     *
     * @param serStr
     *            字符串
     * @return 反序列化结果
     */
    public static Object DeSerializeFromString(String serStr) {
        Object obj = null;

        if (null == serStr || serStr.isEmpty()) {
            log.error("DeSerializeFromString input serStr is empty!");
            return serStr;
        }

        ByteArrayInputStream byteArrayInStream = null;
        ObjectInputStream objInStream = null;

        try {
            serStr = URLDecoder.decode(serStr, "UTF-8");
            byteArrayInStream = new ByteArrayInputStream(serStr.getBytes("ISO-8859-1"));
            objInStream = new ObjectInputStream(byteArrayInStream);
            obj = objInStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != objInStream) {
                try {
                    objInStream.close();
                } catch (IOException e) {
                }
            }
            if (null != byteArrayInStream) {
                try {
                    byteArrayInStream.close();
                } catch (IOException e) {
                }
            }
        }
        return obj;
    }

}
